package com

/**
 * @Author      : xingnan
 * @Email       : 457415936@qq.com
 * @Time        : 17:18
 * @File        : strings.go
 * @Project     : toolbox
 * @Description : 字符串处理
 */
import (
	"bytes"
	"fmt"
	"math/bits"
	"math/rand"
	"strconv"
	"strings"
	"time"
)

// ByteCat return bytes.
func ByteCat(sv ...string) []byte {
	var buf bytes.Buffer
	var size int
	for _, s := range sv {
		size += len(s)
	}
	buf.Grow(size)
	for _, s := range sv {
		_, _ = buf.WriteString(s)
	}
	return buf.Bytes()
}

// StrCat cat strings:
// You should know that StrCat gradually builds advantages
// only when the number of parameters is> 2.
func StrCat(sv ...string) string {
	var sb strings.Builder
	var size int
	for _, s := range sv {
		size += len(s)
	}
	sb.Grow(size)
	for _, s := range sv {
		_, _ = sb.WriteString(s)
	}
	return sb.String()
}

// StrSplitSkipEmpty skip empty string suggestcap is suggest cap
func StrSplitSkipEmpty(s string, sep byte, suggestcap int) []string {
	sv := make([]string, 0, suggestcap)
	var first, i int
	for ; i < len(s); i++ {
		if s[i] != sep {
			continue
		}
		if first != i {
			sv = append(sv, s[first:i])
		}
		first = i + 1
	}
	if first < len(s) {
		sv = append(sv, s[first:])
	}
	return sv
}

// PathSplit split path and
func PathSplit(p string, suggestcap int) []string {
	pv := make([]string, 0, suggestcap)
	var first, i int
	for ; i < len(p); i++ {
		if p[i] != '/' {
			continue
		}
		if first != i {
			s := p[first:i]
			switch s {
			case ".":
			case "..":
				if len(pv) == 0 {
					return pv
				}
				pv = pv[0 : len(pv)-1]
			default:
				pv = append(pv, s)
			}
		}
		first = i + 1
	}
	if first < len(p) {
		s := p[first:i]
		switch s {
		case ".":
		case "..":
			if len(pv) == 0 {
				return pv
			}
			pv = pv[0 : len(pv)-1]
		default:
			pv = append(pv, s)
		}
	}
	return pv
}

// StrSplitSkipSpecNoEmpty todo
func StrSplitSkipSpecNoEmpty(s, spec string, sep byte, suggestcap int) []string {
	sv := StrSplitSkipEmpty(s, sep, suggestcap)
	sv2 := make([]string, 0, suggestcap)
	for _, s := range sv {
		if s != spec {
			sv2 = append(sv2, s)
		}
	}
	return sv2
}

// HasNonBmpRune todo
// BMP -> U+0000 to U+FFFF
// https://www.sttmedia.com/unicode-basiclingualplane
func HasNonBmpRune(s string) bool {
	// ==> for _, v := range []rune(s)
	// https://github.com/golang/go/blob/c2edcf4b1253fdebc13df8a25979904c3ef01c66/src/cmd/compile/internal/gc/range.go#L358
	for _, r := range s {
		if r > '\uFFFF' {
			return true
		}
	}
	return false
}

const hdigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

func escapeRune(sb *strings.Builder, r rune) {
	var a [32 + 1]byte
	i := len(a)
	shift := uint(bits.TrailingZeros(uint(16))) & 7
	b := uint64(16)
	m := uint(16) - 1 // == 1<<shift - 1
	u := uint64(r)
	for u >= b {
		i--
		a[i] = hdigits[uint(u)&m]
		u >>= shift
	}
	// u < base
	i--
	a[i] = hdigits[uint(u)]
	sl := len(a) - i
	_, _ = sb.WriteString("\\U")
	for i := 0; i < 8-sl; i++ {
		_ = sb.WriteByte('0')
	}
	_, _ = sb.Write(a[i:])
}

// EscapeNonBmpRune escape non BMP rune
func EscapeNonBmpRune(s string) string {
	var sb strings.Builder
	sb.Grow(len(s))
	for _, r := range s {
		if r == '\\' {
			_, _ = sb.Write([]byte(`\\`))
			continue
		}
		if r > '\uFFFF' {
			escapeRune(&sb, r)
			continue
		}
		_, _ = sb.WriteRune(r)
	}
	return sb.String()
}

//小写转大写
func ToUpper(str string) string {
	return strings.ToUpper(str)
}

//大写转小写
func ToLower(str string) string {
	return strings.ToLower(str)
}

//补齐
//strs 需要补齐字符串
//length 补齐长度
//pad 补齐的字符串
//补齐方向 left左补齐；right右补齐
func Str_Pad(strs string, length int, pad string, up string) (str string) {
	//计算长度
	if len(strings.TrimSpace(strs)) >= length {
		return strs
	}

	pads := strings.Repeat(pad, length-len(strs))

	//进行补齐
	switch up {
	case "left": //左补齐
		str = pads + strings.TrimSpace(strs)
		break
	case "right": //右补齐
		str = strings.TrimSpace(strs) + pads
		break
	}
	return str

}

// 截取子串
func SubString(str string, begin, length int) (substr string) {
	rs := []rune(str)
	lth := len(rs)

	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}

	return string(rs[begin:end])
}

// 创建随机串
func RandString(n int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < n; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

//str 转为float64并
func StrToFloat64(str string) float64 {
	StrToFloat64, _ := strconv.ParseFloat(str, 64)
	return StrToFloat64
}

//float64转为str并保留2位小数
func Float64ToStr(str float64) string {
	return strconv.FormatFloat(str, 'f', 2, 64)
}

//生成随机KEY
func MakeRandomStr() string {
	times := time.Now().Unix()
	timetostr := fmt.Sprintf("%s", times)
	return ToSha1(timetostr)
}
